/*!
 * \file HisDataReplayer.h
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief 历史数据回放器头文件
 * 
 * 本文件定义了历史数据回放器的核心类和接口，主要功能包括：
 * 1. 历史行情数据的回放和模拟
 * 2. 多种数据源的支持（文件、外部加载器等）
 * 3. K线、Tick、委托队列、委托明细、成交明细等数据回放
 * 4. 复权因子的处理和应用
 * 5. 回测任务的调度和管理
 * 6. 高频数据的精确时间控制
 * 
 * HisDataReplayer是WonderTrader回测系统的核心组件，
 * 负责将历史数据按时间顺序回放给策略引擎。
 */
#pragma once
#include <string>
#include "HisDataMgr.h"
#include "../WtDataStorage/DataDefine.h"

#include "../Includes/FasterDefs.h"
#include "../Includes/WTSMarcos.h"
#include "../Includes/WTSTypes.h"

#include "../WTSTools/WTSHotMgr.h"
#include "../WTSTools/WTSBaseDataMgr.h"

NS_WTP_BEGIN
class WTSTickData;
class WTSVariant;
class WTSKlineSlice;
class WTSTickSlice;
class WTSOrdDtlSlice;
class WTSOrdQueSlice;
class WTSTransSlice;
class WTSSessionInfo;
class WTSCommodityInfo;

class WTSOrdDtlData;
class WTSOrdQueData;
class WTSTransData;

class EventNotifier;
NS_WTP_END

USING_NS_WTP;

/**
 * @class IDataSink
 * @brief 数据接收器接口
 * 
 * 数据接收器接口定义了回放器向外部推送数据的回调方法，
 * 策略引擎或其他组件可以实现此接口来接收回放的历史数据。
 * 
 * 支持的数据类型包括：
 * - Tick数据：逐笔行情数据
 * - 委托队列：Level2委托队列数据
 * - 委托明细：Level2委托明细数据
 * - 成交明细：Level2成交明细数据
 * - K线闭合：K线周期结束事件
 * - 调度事件：定时任务触发事件
 * - 生命周期事件：初始化、交易时段开始/结束等
 */
class IDataSink
{
public:
	/**
	 * @brief 处理Tick数据
	 * @param stdCode 标准合约代码
	 * @param curTick 当前Tick数据
	 * 
	 * 接收回放的Tick数据，实现者需要处理逐笔行情数据
	 */
	virtual void	handle_tick(const char* stdCode, WTSTickData* curTick) = 0;
	
	/**
	 * @brief 处理委托队列数据
	 * @param stdCode 标准合约代码
	 * @param curOrdQue 当前委托队列数据
	 * 
	 * 接收回放的Level2委托队列数据，默认空实现
	 */
	virtual void	handle_order_queue(const char* stdCode, WTSOrdQueData* curOrdQue) {};
	
	/**
	 * @brief 处理委托明细数据
	 * @param stdCode 标准合约代码
	 * @param curOrdDtl 当前委托明细数据
	 * 
	 * 接收回放的Level2委托明细数据，默认空实现
	 */
	virtual void	handle_order_detail(const char* stdCode, WTSOrdDtlData* curOrdDtl) {};
	
	/**
	 * @brief 处理成交明细数据
	 * @param stdCode 标准合约代码
	 * @param curTrans 当前成交明细数据
	 * 
	 * 接收回放的Level2成交明细数据，默认空实现
	 */
	virtual void	handle_transaction(const char* stdCode, WTSTransData* curTrans) {};
	
	/**
	 * @brief 处理K线闭合事件
	 * @param stdCode 标准合约代码
	 * @param period K线周期字符串
	 * @param times 周期倍数
	 * @param newBar 新生成的K线数据
	 * 
	 * 接收K线周期结束事件，通知新K线的生成
	 */
	virtual void	handle_bar_close(const char* stdCode, const char* period, uint32_t times, WTSBarStruct* newBar) = 0;
	
	/**
	 * @brief 处理调度事件
	 * @param uDate 日期
	 * @param uTime 时间
	 * 
	 * 接收定时调度事件，用于定时任务的执行
	 */
	virtual void	handle_schedule(uint32_t uDate, uint32_t uTime) = 0;

	/**
	 * @brief 处理初始化事件
	 * 
	 * 回放开始前的初始化回调
	 */
	virtual void	handle_init() = 0;
	
	/**
	 * @brief 处理交易时段开始事件
	 * @param curTDate 当前交易日
	 * 
	 * 交易时段开始时的回调
	 */
	virtual void	handle_session_begin(uint32_t curTDate) = 0;
	
	/**
	 * @brief 处理交易时段结束事件
	 * @param curTDate 当前交易日
	 * 
	 * 交易时段结束时的回调
	 */
	virtual void	handle_session_end(uint32_t curTDate) = 0;
	
	/**
	 * @brief 处理回放完成事件
	 * 
	 * 历史数据回放完成时的回调，默认空实现
	 */
	virtual void	handle_replay_done() {}
};

/**
 * @brief K线数据读取回调函数类型
 * @param obj 回调对象，原始调用方传入
 * @param firstBar 第一根K线指针
 * @param count K线数量
 * 
 * 用于历史K线数据加载的回调函数类型定义
 */
typedef void(*FuncReadBars)(void* obj, WTSBarStruct* firstBar, uint32_t count);

/**
 * @brief 复权因子读取回调函数类型
 * @param obj 回调对象，原始调用方传入
 * @param stdCode 合约代码
 * @param dates 日期数组
 * @param factors 因子数组
 * @param count 数据条数
 * 
 * 用于复权因子数据加载的回调函数类型定义
 */
typedef void(*FuncReadFactors)(void* obj, const char* stdCode, uint32_t* dates, double* factors, uint32_t count);

/**
 * @brief Tick数据读取回调函数类型
 * @param obj 回调对象，原始调用方传入
 * @param firstTick 第一个Tick指针
 * @param count Tick数量
 * 
 * 用于历史Tick数据加载的回调函数类型定义
 */
typedef void(*FuncReadTicks)(void* obj, WTSTickStruct* firstTick, uint32_t count);

/**
 * @class IBtDataLoader
 * @brief 回测数据加载器接口
 * 
 * 回测数据加载器接口定义了外部数据源的加载方法，
 * 支持从数据库、文件或其他数据源加载历史数据。
 * 
 * 主要功能包括：
 * 1. 最终K线数据加载（经过复权处理）
 * 2. 原始K线数据加载（未经复权处理）
 * 3. 复权因子数据加载
 * 4. 历史Tick数据加载
 * 5. 主力合约自动转换控制
 */
class IBtDataLoader
{
public:
	/**
	 * @brief 加载最终历史K线数据
	 * @param obj 回调对象，原始调用方传入
	 * @param stdCode 合约代码
	 * @param period K线周期
	 * @param cb 回调函数
	 * @return 是否加载成功
	 * 
	 * 加载经过处理的最终K线数据，包括复权处理、主力合约连接等。
	 * loadFinalHisBars在系统认为需要进行数据处理时调用，用于加工处理复权数据、连续合约等。
	 * 与loadRawHisBars相对应，这是加载已加工的最终数据的接口。
	 */
	virtual bool loadFinalHisBars(void* obj, const char* stdCode, WTSKlinePeriod period, FuncReadBars cb) = 0;

	/**
	 * @brief 加载原始历史K线数据
	 * @param obj 回调对象，原始调用方传入
	 * @param stdCode 合约代码
	 * @param period K线周期
	 * @param cb 回调函数
	 * @return 是否加载成功
	 * 
	 * 加载未经加工的原始K线数据，用于获取最原始的行情数据
	 */
	virtual bool loadRawHisBars(void* obj, const char* stdCode, WTSKlinePeriod period, FuncReadBars cb) = 0;

	/**
	 * @brief 加载全部复权因子
	 * @param obj 回调对象
	 * @param cb 回调函数
	 * @return 是否加载成功
	 * 
	 * 加载系统中所有合约的复权因子数据
	 */
	virtual bool loadAllAdjFactors(void* obj, FuncReadFactors cb) = 0;

	/**
	 * @brief 根据合约加载复权因子
	 * @param obj 回调对象
	 * @param stdCode 合约代码
	 * @param cb 回调函数
	 * @return 是否加载成功
	 * 
	 * 加载指定合约的复权因子数据
	 */
	virtual bool loadAdjFactors(void* obj, const char* stdCode, FuncReadFactors cb) = 0;

	/**
	 * @brief 加载历史Tick数据
	 * @param obj 回调对象
	 * @param stdCode 合约代码
	 * @param uDate 日期
	 * @param cb 回调函数
	 * @return 是否加载成功
	 * 
	 * 加载指定日期的历史Tick数据
	 */
	virtual bool loadRawHisTicks(void* obj, const char* stdCode, uint32_t uDate, FuncReadTicks cb) = 0;

	/**
	 * @brief 是否支持自动主力合约转换
	 * @return 是否支持自动转换
	 * 
	 * 返回数据加载器是否支持主力合约的自动转换，默认支持
	 */
	virtual bool isAutoTrans() { return true; }
};

class HisDataReplayer
{

private:
	template <typename T>
	class HftDataList
	{
	public:
		std::string		_code;
		uint32_t		_date;
		/*
		 * By Wesley @ 2022.03.21
		 * 改进，在第一次调用时初始化，所以说是已经初始化过的
		 * 如果没有开始，则初始化为UINT_MAX，一旦开始，则初始化为0，
		 */
		std::size_t		_cursor;
		std::size_t		_count;

		std::vector<T> _items;

		HftDataList() :_cursor(UINT_MAX), _count(0), _date(0){}
	};

	typedef faster_hashmap<std::string, HftDataList<WTSTickStruct>>		TickCache;
	typedef faster_hashmap<std::string, HftDataList<WTSOrdDtlStruct>>	OrdDtlCache;
	typedef faster_hashmap<std::string, HftDataList<WTSOrdQueStruct>>	OrdQueCache;
	typedef faster_hashmap<std::string, HftDataList<WTSTransStruct>>	TransCache;


	typedef struct _BarsList
	{
		std::string		_code;
		WTSKlinePeriod	_period;
		/*
		 * By Wesley @ 2022.03.21
		 * 改进，在第一次调用时初始化，所以说是已经初始化过的
		 * 如果没有开始，则初始化为UINT_MAX，一旦开始，则初始化为0，
		 */
		uint32_t		_cursor;
		uint32_t		_count;
		uint32_t		_times;

		std::vector<WTSBarStruct>	_bars;
		double			_factor;	//第一个复权因子

		_BarsList() :_cursor(UINT_MAX), _count(0), _times(1), _factor(1){}
	} BarsList;

	/*
	 *	By Wesley @ 2022.03.13
	 *	为了防止用户在oncalc时取到未初始化的oninit的K线，
	 *	为了使用BarList，K线必须先map再append
	 *	否则会失效，所以必须先map再append
	 *	如果一个BarList被多个线程使用，则必须加锁，
	 *	否则会出错，因为map和append的地址是不可重用的
	 */
	typedef std::shared_ptr<BarsList> BarsListPtr;
	typedef faster_hashmap<std::string, BarsListPtr>	BarsCache;

	typedef enum tagTaskPeriodType
	{
		TPT_None,		//每天
		TPT_Minute = 4,	//每分钟
		TPT_Daily = 8,	//每天,每天都要
		TPT_Weekly,		//每天,每天都要
		TPT_Monthly,	//每天,每天都要
		TPT_Yearly		//每天,每天都要
	}TaskPeriodType;

	typedef struct _TaskInfo
	{
		uint32_t	_id;
		char		_name[16];		//任务名
		char		_trdtpl[16];	//任务模板
		char		_session[16];	//时间模板
		uint32_t	_day;			//天,天会变化,每天为0,每天为0~6,对应星期,每天为1~31,每天为0101~1231
		uint32_t	_time;			//时间,精确到秒
		bool		_strict_time;	//是否严格时间,严格时间则只执行时间不执行,否则所有时间都执行

		uint64_t	_last_exe_time;	//上次执行时间,要为防止重复执行

		TaskPeriodType	_period;	//任务周期
	} TaskInfo;

	typedef std::shared_ptr<TaskInfo> TaskInfoPtr;



public:
	HisDataReplayer();
	~HisDataReplayer();

private:
	/*
	 *	从二进制文件加载K线数据
	 */
	bool		cacheRawBarsFromBin(const std::string& key, const char* stdCode, WTSKlinePeriod period, bool bForBars = true);

	/*
	 *	从csv文件加载K线数据
	 */
	bool		cacheRawBarsFromCSV(const std::string& key, const char* stdCode, WTSKlinePeriod period, bool bSubbed = true);

	/*
	 *	从二进制文件加载tick数据
	 */
	bool		cacheRawTicksFromBin(const std::string& key, const char* stdCode, uint32_t uDate);

	/*
	 *	从csv文件加载tick数据
	 */
	bool		cacheRawTicksFromCSV(const std::string& key, const char* stdCode, uint32_t uDate);

	/*
	 *	从外部加载器加载最终K线数据
	 */
	bool		cacheFinalBarsFromLoader(const std::string& key, const char* stdCode, WTSKlinePeriod period, bool bSubbed = true);

	/*
	 *	从外部加载器加载tick数据
	 */
	bool		cacheRawTicksFromLoader(const std::string& key, const char* stdCode, uint32_t uDate);

	/*
	 *	从外部加载器加载最终K线数据
	 */
	bool		cacheIntegratedFutBarsFromBin(const std::string& key, const char* stdCode, WTSKlinePeriod period, bool bSubbed = true);

	/*
	 *	从外部加载器加载复权K线数据
	 */
	bool		cacheAdjustedStkBarsFromBin(const std::string& key, const char* stdCode, WTSKlinePeriod period, bool bSubbed = true);

	void		onMinuteEnd(uint32_t uDate, uint32_t uTime, uint32_t endTDate = 0, bool tickSimulated = true);

	void		loadFees(const char* filename);

	bool		replayHftDatas(uint64_t stime, uint64_t etime);

	uint64_t	replayHftDatasByDay(uint32_t curTDate);

	void		replayUnbars(uint64_t stime, uint64_t etime, uint32_t endTDate = 0);

	inline bool		checkTicks(const char* stdCode, uint32_t uDate);

	inline bool		checkOrderDetails(const char* stdCode, uint32_t uDate);

	inline bool		checkOrderQueues(const char* stdCode, uint32_t uDate);

	inline bool		checkTransactions(const char* stdCode, uint32_t uDate);

	void		checkUnbars();

	bool		loadStkAdjFactorsFromFile(const char* adjfile);

	bool		loadStkAdjFactorsFromLoader();

	bool		checkAllTicks(uint32_t uDate);

	inline	uint64_t	getNextTickTime(uint32_t curTDate, uint64_t stime = UINT64_MAX);
	inline	uint64_t	getNextOrdQueTime(uint32_t curTDate, uint64_t stime = UINT64_MAX);
	inline	uint64_t	getNextOrdDtlTime(uint32_t curTDate, uint64_t stime = UINT64_MAX);
	inline	uint64_t	getNextTransTime(uint32_t curTDate, uint64_t stime = UINT64_MAX);

	void		reset();


	void		dump_btstate(const char* stdCode, WTSKlinePeriod period, uint32_t times, uint64_t stime, uint64_t etime, double progress, int64_t elapse);
	void		notify_state(const char* stdCode, WTSKlinePeriod period, uint32_t times, uint64_t stime, uint64_t etime, double progress);

	uint32_t	locate_barindex(const std::string& key, uint64_t curTime, bool bUpperBound = false);

	/*
	 *	按K线回放
	 *
	 *	@bNeedDump	是否需要输出到文件
	 */
	void	run_by_bars(bool bNeedDump = false);

	/*
	 *	按任务回放
	 *
	 *	@bNeedDump	是否需要输出到文件
	 */
	void	run_by_tasks(bool bNeedDump = false);

	/*
	 *	按tick回放
	 *
	 *	@bNeedDump	是否需要输出到文件
	 */
	void	run_by_ticks(bool bNeedDump = false);

public:
	bool init(WTSVariant* cfg, EventNotifier* notifier = NULL, IBtDataLoader* dataLoader = NULL);

	bool prepare();

	/*
	 *	回放
	 *
	 *	@bNeedDump	是否需要输出到文件
	 */
	void run(bool bNeedDump = false);
	
	void stop();

	void clear_cache();

	inline void set_time_range(uint64_t stime, uint64_t etime)
	{
		_begin_time = stime;
		_end_time = etime;
	}

	inline void enable_tick(bool bEnabled = true)
	{
		_tick_enabled = bEnabled;
	}

	inline void register_sink(IDataSink* listener, const char* sinkName) 
	{
		_listener = listener; 
		_stra_name = sinkName;
	}

	void register_task(uint32_t taskid, uint32_t date, uint32_t time, const char* period, const char* trdtpl = "CHINA", const char* session = "TRADING");

	WTSKlineSlice* get_kline_slice(const char* stdCode, const char* period, uint32_t count, uint32_t times = 1, bool isMain = false);

	WTSTickSlice* get_tick_slice(const char* stdCode, uint32_t count, uint64_t etime = 0);

	WTSOrdDtlSlice* get_order_detail_slice(const char* stdCode, uint32_t count, uint64_t etime = 0);

	WTSOrdQueSlice* get_order_queue_slice(const char* stdCode, uint32_t count, uint64_t etime = 0);

	WTSTransSlice* get_transaction_slice(const char* stdCode, uint32_t count, uint64_t etime = 0);

	WTSTickData* get_last_tick(const char* stdCode);

	uint32_t get_date() const{ return _cur_date; }
	uint32_t get_min_time() const{ return _cur_time; }
	uint32_t get_raw_time() const{ return _cur_time; }
	uint32_t get_secs() const{ return _cur_secs; }
	uint32_t get_trading_date() const{ return _cur_tdate; }

	double calc_fee(const char* stdCode, double price, double qty, uint32_t offset);
	WTSSessionInfo*		get_session_info(const char* sid, bool isCode = false);
	WTSCommodityInfo*	get_commodity_info(const char* stdCode);
	double get_cur_price(const char* stdCode);

	void sub_tick(uint32_t sid, const char* stdCode);
	void sub_order_queue(uint32_t sid, const char* stdCode);
	void sub_order_detail(uint32_t sid, const char* stdCode);
	void sub_transaction(uint32_t sid, const char* stdCode);

	inline bool	is_tick_enabled() const{ return _tick_enabled; }

	inline bool	is_tick_simulated() const { return _tick_simulated; }

	inline void update_price(const char* stdCode, double price)
	{
		_price_map[stdCode] = price;
	}

private:
	IDataSink*		_listener;
	IBtDataLoader*	_bt_loader;
	std::string		_stra_name;

	TickCache		_ticks_cache;	//tick缓存
	OrdDtlCache		_orddtl_cache;	//order detail缓存
	OrdQueCache		_ordque_cache;	//order queue缓存
	TransCache		_trans_cache;	//transaction缓存

	BarsCache		_bars_cache;	//K线缓存
	BarsCache		_unbars_cache;	//未完成的K线缓存

	TaskInfoPtr		_task;

	std::string		_main_key;
	std::string		_min_period;	//最小K线周期,如果要处理未平仓的品种，则需要订阅该品种的信号
	bool			_tick_enabled;	//是否需要回放tick
	bool			_tick_simulated;	//是否需要模拟tick
	std::map<std::string, WTSTickStruct>	_day_cache;	//每天Tick缓存,如果tick已经过期,则该线程的线程缓存
	std::map<std::string, std::string>		_ticker_keys;

	uint32_t		_cur_date;
	uint32_t		_cur_time;
	uint32_t		_cur_secs;
	uint32_t		_cur_tdate;
	uint32_t		_closed_tdate;
	uint32_t		_opened_tdate;

	WTSBaseDataMgr	_bd_mgr;
	WTSHotMgr		_hot_mgr;

	std::string		_base_dir;
	std::string		_mode;
	uint64_t		_begin_time;
	uint64_t		_end_time;

	bool			_running;
	bool			_terminated;
	//////////////////////////////////////////////////////////////////////////
	//费用模型
	typedef struct _FeeItem
	{
		double	_open;
		double	_close;
		double	_close_today;
		bool	_by_volume;

		_FeeItem()
		{
			memset(this, 0, sizeof(_FeeItem));
		}
	} FeeItem;
	typedef faster_hashmap<std::string, FeeItem>	FeeMap;
	FeeMap		_fee_map;

	//////////////////////////////////////////////////////////////////////////
	//
	typedef faster_hashmap<std::string, double> PriceMap;
	PriceMap		_price_map;

	//////////////////////////////////////////////////////////////////////////
	//
	typedef faster_hashset<uint32_t> SIDSet;
	typedef faster_hashmap<std::string, SIDSet>	StraSubMap;
	StraSubMap		_tick_sub_map;		//tick数据订阅
	StraSubMap		_ordque_sub_map;	//orderqueue数据订阅
	StraSubMap		_orddtl_sub_map;	//orderdetail数据订阅
	StraSubMap		_trans_sub_map;		//transaction数据订阅

	//复权因子
	typedef struct _AdjFactor
	{
		uint32_t	_date;
		double		_factor;
	} AdjFactor;
	typedef std::vector<AdjFactor> AdjFactorList;
	typedef faster_hashmap<std::string, AdjFactorList>	AdjFactorMap;
	AdjFactorMap	_adj_factors;

	const AdjFactorList& getAdjFactors(const char* code, const char* exchg, const char* pid);

	EventNotifier*	_notifier;

	HisDataMgr		_his_dt_mgr;
};

